﻿using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTKBasics.AssimpNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OpenTKBasics
{
    // So you've drawn the first triangle. But what about drawing multiple?
    // You may consider just adding more vertices to the array, and that would technically work, but say you're drawing a rectangle.
    // It only needs four vertices, but since OpenGL works in triangles, you'd need to define 6.
    // Not a huge deal, but it quickly adds up when you get to more complex models. For example, a cube only needs 8 vertices, but
    // doing it that way would need 36 vertices!

    // OpenGL provides a way to reuse vertices, which can heavily reduce memory usage on complex objects.
    // This is called an Element Buffer Object. This tutorial will be all about how to set one up.
    public class Game7 : GameWindow
    {
        // We modify the vertex array to include four vertices for our rectangle.
        private readonly float[] _vertices =
        {
             0.5f,  0.5f, 0.0f, 1.0f,0.0f,0.0f,  1.0f, 1.0f,  // top right
             0.5f, -0.5f, 0.0f, 0.0f,1.0f,0.0f,  1.0f, 0.0f,  // bottom right
            -0.5f, -0.5f, 0.0f, 0.0f,0.0f,1.0f,  0.0f, 0.0f,  // bottom left
            -0.5f,  0.5f, 0.0f, 0.0f,0.0f,1.0f,  0.0f, 1.0f,  // top left
        };

        // Then, we create a new array: indices. 
        // This array controls how the EBO will use those vertices to create triangles
        private readonly uint[] _indices =
        {
            // Note that indices start at 0!
            0, 1, 3, // The first triangle will be the bottom-right half of the triangle
            1, 2, 3  // Then the second will be the top-right half of the triangle
        };

        private int _vertexBufferObject;
        private int _vertexArrayObject;
        // Add a handle for the EBO
        private int _elementBufferObject;

        private Shader _shader;
        private Camera _camera;
        private Texture2 _texture;
        private Mesh cube;
        private Model model ;


        float aspect = 2.0f;
        double timeValue = 0.0d;
        Matrix4 transform;

        /// <summary>
        /// 主窗体设置启动
        /// </summary>
        /// <param name="width">开启时宽度</param>
        /// <param name="height">开启时高度</param>
        /// <param name="title">窗体标题</param>
        public Game7(int width = 1920, int height = 1080, string title = "Game7")
            : base(
                  GameWindowSettings.Default, 
                  new NativeWindowSettings()
                        {
                          Size = new Vector2i(width, height),
                          Title = title,
                          // This is needed to run on macos
                          Flags = ContextFlags.ForwardCompatible,
                          WindowBorder = WindowBorder.Fixed,                    
                          StartFocused = true,
                          API = ContextAPI.OpenGL,
                          Profile = ContextProfile.Core,
                          APIVersion = new Version(3, 3),

                          //StartVisible = false,  //请勿开启 危险
                      }
                  )
        {
            this.CenterWindow();
        }

        /// <summary>
        /// 初始化加载时
        /// </summary>
        protected override void OnLoad()
        {
            base.OnLoad();

            _shader = new Shader("shader/shader.vert", "shader/shader.frag");
            _shader.Use();
             
            GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);

            //_texture = new Texture2(0);
            //_texture = _texture.LoadFromFile("texture/wood.jpg");
            //_texture.Use(TextureUnit.Texture0);

            string suitModelPath = "model/nanosuit/nanosuit.obj";
            string gisModelPath = "model/gis/GIS.obj";
            cube = new Mesh(_shader,_vertices, _indices );
            model =new Model(_shader, gisModelPath);
             
            //相机生成
            _camera = new Camera(3.0f * Vector3.UnitZ, aspect);

        }


        /// <summary>
        /// 每次渲染事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);

            GL.Clear(ClearBufferMask.ColorBufferBit);
             

            cube.Draw();
            model.Draw();

            SwapBuffers();
        }

        /// <summary>
        /// 每帧更新事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);

            {
                //对shader传值 导致颜色变化
                timeValue += 0.00d;
                float greenValue = (float)Math.Sin(timeValue) / (2.0f + 0.5f);
                int vertexColorLocation = GL.GetUniformLocation(this._shader.GetHandle(), "uColor");
                GL.Uniform4(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
              
                //定义模型变换矩阵
                Matrix4 scale = Matrix4.CreateScale(0.5f, 0.5f, 0.5f);
                Matrix4 rotation = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(100.0f));
                Matrix4 trans = Matrix4.CreateTranslation(-0.5f, 0.2f, 0.0f);
                transform = trans * rotation * scale;

                //矩阵整合进入shader 对shader传矩阵
                float rotValue = (float)Math.Sin(timeValue) * 80.0f;
                Matrix4 model = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(rotValue));
                model *= transform;
                Matrix4 view = _camera.GetViewMatrix();
                Matrix4 projection = _camera.GetProjectionMatrix();
                this._shader.SetMatrix4("model", model);
                this._shader.SetMatrix4("view", view);
                this._shader.SetMatrix4("projection", projection);
                //Console.WriteLine("UPDATE");
            }
             
            //input
            {
                // Check to see if the window is focused  看看是否定位到当前窗口 否则按键不起效用
                if (!IsFocused) { return; }
                KeyboardState input = KeyboardState;
                if (input.IsKeyDown(Keys.Escape)) { Close(); }
                _camera.KeyControllor(input, e);

                MouseState mouse = MouseState;
                _camera.MouseMoveControllor(mouse);
            }

        }

        /// <summary>
        /// 调整窗口大小事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnResize(ResizeEventArgs e)
        {
            base.OnResize(e);
            //实时获得并调整宽高比
            aspect = e.Width / (float)e.Height;
            GL.Viewport(0, 0, e.Width, e.Height);
        }

        /// <summary>
        /// 卸载事件
        /// </summary>
        protected override void OnUnload()
        {
            base.OnUnload();

            GL.BindVertexArray(0);
            GL.DeleteVertexArray(this._vertexArrayObject);

            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.DeleteBuffer(this._vertexBufferObject);

            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
            GL.DeleteBuffer(this._elementBufferObject);

            _shader.Dispose();
        }

        /// <summary>
        /// 鼠标滚轮事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseWheel(MouseWheelEventArgs e)
        {
            base.OnMouseWheel(e);
            _camera.Fov -= e.OffsetY;
        }

    }
}
